home *** CD-ROM | disk | FTP | other *** search
/ Belgian Amiga Club - ADF Collection / BS1 part 19.zip / BS1 part 19 / AmigaLibDisk 161.adf / LGZ / StdFile.c < prev    next >
C/C++ Source or Header  |  1988-10-02  |  22KB  |  941 lines

  1. /* STDFILE -- Standard File Requestor. Version 2.0a 15 June 1987
  2.  *
  3.  * AUTHOR -- Peter da Silva      US (713) 497-4372
  4.  *
  5.  * Copyright (c) 1987 Peter da Silva, all rights reserved.
  6.  *
  7.  *    This module may be freely used in any product, commercial or
  8.  *    otherwise, provided credit is given for this module and
  9.  *    and provided this notice remains intact in the source. The
  10.  *    intent of this module is to provide a standard file requestor
  11.  *    such as is available on the Macintosh, in GEM on the IBM-PC
  12.  *    and Atari ST, and in the Microsoft Windows software on the
  13.  *    IBM-PC. The advantage this module has over other requestors
  14.  *    is that it minimises disk accesses: an important consideration
  15.  *    given the structure of AmigaDos directories. If you need to
  16.  *    modify it for your needs, by all means go ahead... but please
  17.  *    conform to the intent of this program as stated above. If you
  18.  *    have suggestions for improvements, by all means call me at
  19.  *    the number listed above.
  20.  *
  21.  * Enhancements in the current version:
  22.  *
  23.  *    Gadgets now boxed. Display generally cleaned up.
  24.  *
  25.  *    True "dictionary order" for searches.
  26.  *
  27.  *    Default pattern can now be specified. Default file name now
  28.  *    specified in a single argument.
  29.  *
  30.  *    Directories always match.
  31.  *
  32.  *    Null pattern converted to "#?" universal wildcard.
  33.  *
  34.  *    If you attempt to build a file name longer than 128 characters the
  35.  *    screen will flash and the operation will be aborted.
  36.  *
  37.  *    "Volumes" gadget, using the device list code in "mounted". This
  38.  *    gadget brings up a list of all currently mounted volumes for
  39.  *    selection. Volumes leaves the directory specification intact, so
  40.  *    you can quickly return to where you left off.
  41.  *
  42.  *    "Parent" gadget, displays parent directory.
  43.  *
  44.  *    With these enhancements it is now possible to select any file on
  45.  *    any device without touching the keyboard. This is now release 2.0,
  46.  *    as it is significantly better than 1.0.
  47.  *
  48.  * Acknowledgements:
  49.  *
  50.  *    Thanks to Jeff Lydiatt for the pattern matching code in PatMatch.c
  51.  *    Thanks to Jay Miner, =RJ= and the whole Amiga team for the Amiga
  52.  *    itself.
  53.  *
  54.  * Environment:
  55.  *
  56.  *    IntuitionBase and GfxBase must be open. dos.library must be open
  57.  *    under the name "DOSBase". Link with PatMatch.o and VolList.o.
  58.  *
  59.  * Usage:
  60.  *
  61.  *    #define MAXFILENAME 128
  62.  *
  63.  *    int stdfile(title, default_file, default_pat, name);
  64.  *    char *title;
  65.  *    char *default_file;
  66.  *    char *default_pattern;
  67.  *    char name[MAXFILENAME];
  68.  *
  69.  *    struct Screen *stdscreen;
  70.  *
  71.  *    STDFILE puts up a file requestor (actually, it's a plain window)
  72.  *    in stdscreen. If stdscreen is NULL, the workbench screen is used.
  73.  *    The requestor looks like this (allowing for the limitations of
  74.  *    text):
  75.  *
  76.  *    +-----------------------------------+
  77.  *    |o| Title ------------------- |  |  | title parameter, or "File Name"
  78.  *    |-----------------------------------|
  79.  *    | Directory: [                    ] | Directory parameter, or current.
  80.  *    | File name: [                    ] | Default parameter, or empty.
  81.  *    | Pattern:   [                    ] | Initially empty, if the user
  82.  *    | +-------------------------------+ | enters anything here it will
  83.  *    | | [Filename]                 |  | | be used to select files. The
  84.  *    | | [Filename]                 |  | | file display will also be empty
  85.  *    | | [Filename]                 |@@| | to start with to avoid excess
  86.  *    | | [Filename]                 |@@| | disk I/O. If the user selects
  87.  *    | |                            |@@| | here the directory will be
  88.  *    | |                            |@@| | scanned looking for files
  89.  *    | |                            |  | | matching the specified pattern,
  90.  *    | |                            |  | | or "#?" if no pattern is given.
  91.  *    | |                            |  | |
  92.  *    | +-------------------------------+ | ACCEPT returns 1. CANCEL
  93.  *    | [ACCEPT]    [VOLUMES]    [CANCEL] | or the close gadget return 0.
  94.  *    +-----------------------------------+ VOLUMES displays volume names.
  95.  *
  96.  *    The number of filenames displayed is specified at compile time in the
  97.  *    constant MAXFILES. The maximum size of a filename is specified in the
  98.  *    constant MAXNAME. The parameter "Default file" will be broken into
  99.  *    directory and file parts.
  100.  */
  101. char *Copyright =
  102. "stdfile V2.0a. Copyright (c) 1987 Peter da Silva. All rights reserved.";
  103. #include <intuition/intuitionbase.h>
  104. #include <intuition/intuition.h>
  105. #include <libraries/dos.h>
  106. #include <exec/memory.h>
  107.  
  108. /* These four to keep away those bloody warnings: */
  109. void *malloc();
  110. void *OpenWindow();
  111. void *GetMsg();
  112. void *AllocMem();
  113.  
  114. #define MAXFILES 8
  115. #define MAXNAME 32
  116. #define MAXFULL (MAXNAME*4)
  117.  
  118. /* SIZING PARAMS */
  119. #define Z NULL
  120. #define INDENT 6
  121. #define LEFTMAR (INDENT-1)
  122. #define BORDER 3
  123. #define CHSIZ 8
  124. #define HT CHSIZ
  125. #define BASELINE 6
  126. #define BUTWID (6*CHSIZ+INDENT*2)
  127.  
  128. /* GADGET BORDERS */
  129. #define IN1 LEFTMAR+10*CHSIZ
  130. #define IN3 LEFTMAR+3
  131. #define IN4 -(INDENT+6*CHSIZ+1)
  132. #define IN5 -(INDENT+CHSIZ*2)
  133. #define IN6 ((WINWD-BUTWID)/3+INDENT)
  134. #define IN7 (((WINWD-BUTWID)*2)/3+INDENT)
  135. #define WD1 -(INDENT+IN1)
  136. #define WD3 (6*CHSIZ)
  137. #define WD4 (6*CHSIZ)
  138. #define WD5 (CHSIZ*2+2)
  139. #define WD6 (6*CHSIZ)
  140. #define WD7 (6*CHSIZ)
  141. #define TP1 (CHSIZ+BORDER)/*11*/
  142. #define TP2 (TP1+HT+1)/*20*/
  143. #define TP3 (TP2+HT+1)/*29*/
  144. #define TP4 -(BORDER+HT4-1)/*-11*/
  145. #define TP5 (TP3+HT+BORDER)/*40*/
  146. #define HT4 (HT+1)
  147. #define HT5 CHSIZ*MAXFILES+INDENT
  148.  
  149. #define WINHT (TP5 + HT5 + (-TP4) + BORDER) /*40+64+6+11+3*/
  150. #define WINWD (INDENT*    4 + (MAXNAME+2)*CHSIZ) /*24+(32+2)*8 = 296*/
  151. #define WININ 10
  152. #define WINTP 20
  153.  
  154. #define HOMEX (INDENT+LEFTMAR)
  155. #define HOMEY (TP5+BORDER)
  156. #define LASTX (HOMEX+MAXNAME*CHSIZ)
  157. #define LASTY (HOMEY+MAXFILES*CHSIZ)
  158.  
  159. #define BTP TP5
  160. #define BIN LEFTMAR
  161. #define BWD (WINWD-INDENT-BIN)
  162. #define BHT (WINHT-BTP-(-TP4+BORDER+1))
  163.  
  164. #define SF GADGHCOMP|GRELWIDTH
  165. #define SEL SELECTED
  166. #define BF1 GADGHCOMP|GRELBOTTOM
  167. #define BF2 GADGHCOMP|GRELBOTTOM|GRELRIGHT
  168. #define PF GRELRIGHT
  169.  
  170. #define SA RELVERIFY
  171. #define CEN STRINGCENTER
  172. #define BA RELVERIFY
  173. #define PA RELVERIFY
  174.  
  175. #define SI(n) (APTR)&STD_String[n]
  176. #define G(n) &STD_Gadget[n]
  177. #define IMAG (APTR)&STD_Image
  178. #define PROP (APTR)&STD_Prop
  179.  
  180. #define SG STRGADGET
  181. #define BG BOOLGADGET
  182. #define PG PROPGADGET
  183.  
  184. #define FP AUTOBACKPEN
  185. #define BP AUTOFRONTPEN
  186.  
  187. #define OKTEXT &STD_OK
  188. #define NOTEXT &STD_CANCEL
  189. #define VLTEXT &STD_VOLUME
  190. #define PRTEXT &STD_PARENT
  191.  
  192. static int DoneFlag;
  193.  
  194. #define DirName SBuffer[0]
  195. #define FileName SBuffer[1]
  196. #define PatName SBuffer[2]
  197. #define STRINGS 3
  198.  
  199. static UBYTE SBuffer[STRINGS][MAXFULL];
  200. static UBYTE Undo[MAXFULL];
  201.  
  202. static struct StringInfo STD_String[STRINGS] = {
  203.     {SBuffer[0],Undo,0,MAXFULL,0},
  204.     {SBuffer[1],Undo,0,MAXFULL,0},
  205.     {SBuffer[2],Undo,0,MAXFULL,0}
  206. };
  207.  
  208. static struct PropInfo STD_Prop = { AUTOKNOB|FREEVERT, 0, 0, 0, 0 };
  209.  
  210. static struct IntuiText STD_OK =
  211.     { FP, BP, JAM2, 0, 1, Z, (UBYTE *)"ACCEPT", Z };
  212. static struct IntuiText STD_CANCEL =
  213.     { FP, BP, JAM2, 0, 1, Z, (UBYTE *)"CANCEL", Z };
  214. static struct IntuiText STD_VOLUME =
  215.     { FP, BP, JAM2, 0, 1, Z, (UBYTE *)"VOLUME", Z };
  216. static struct IntuiText STD_PARENT =
  217.     { FP, BP, JAM2, 0, 1, Z, (UBYTE *)"PARENT", Z };
  218.  
  219. #define BUTTONS 4
  220. #define BUTVEC 8
  221.  
  222. static SHORT butvecs[BUTTONS][BUTVEC*2] = {
  223.     {
  224.         -2, HT4,
  225.         -2, -1,
  226.         WD3+1,-1,
  227.         WD3+1,HT4,
  228.         -3, HT4,
  229.         -3,-1,
  230.         WD3+2,-1,
  231.         WD3+2, HT4
  232.     },
  233.     {
  234.         -2, HT4,
  235.         -2, -1,
  236.         WD4+1,-1,
  237.         WD4+1,HT4,
  238.         -3, HT4,
  239.         -3,-1,
  240.         WD4+2,-1,
  241.         WD4+2, HT4
  242.     },
  243.     {
  244.         -2, HT4,
  245.         -2, -1,
  246.         WD6+1,-1,
  247.         WD6+1,HT4,
  248.         -3, HT4,
  249.         -3,-1,
  250.         WD6+2,-1,
  251.         WD6+2, HT4
  252.     },
  253.     {
  254.         -2, HT4,
  255.         -2, -1,
  256.         WD7+1,-1,
  257.         WD7+1,HT4,
  258.         -3, HT4,
  259.         -3,-1,
  260.         WD7+2,-1,
  261.         WD7+2, HT4
  262.     }
  263. };
  264. static struct Border ButBorder[BUTTONS] = {
  265.     {0, 0, FP, BP, JAM1, BUTVEC, butvecs[0], NULL},
  266.     {0, 0, FP, BP, JAM1, BUTVEC, butvecs[1], NULL},
  267.     {0, 0, FP, BP, JAM1, BUTVEC, butvecs[2], NULL},
  268.     {0, 0, FP, BP, JAM1, BUTVEC, butvecs[3], NULL}
  269. };
  270. #define BB(n) &ButBorder[n]
  271.  
  272. static struct Image STD_Image;
  273.  
  274. #define DIRID 0
  275. #define FILID 1
  276. #define PATID 2
  277. #define YESID 3
  278. #define CANID 4
  279. #define VOLID 5
  280. #define PARID 6
  281. #define BARID 7
  282. #define GADGETS 8
  283.  
  284. static struct Gadget STD_Gadget[GADGETS] = {
  285. /*NEXT, LFT, TP,WDTH, H, FLAG,  ACT, TYP, REND, Z, TXT, Z, SPEC, ID, Z */
  286. { G(1), IN1,TP1, WD1,HT, SF,     SA,  SG,    Z, Z,   Z, Z, SI(0), 0, 0 },
  287. { G(2), IN1,TP2, WD1,HT, SF|SEL, SA,  SG,    Z, Z,   Z, Z, SI(1), 1, 0 },
  288. { G(3), IN1,TP3, WD1,HT, SF,     SA,  SG,    Z, Z,   Z, Z, SI(2), 2, 0 },
  289. { G(4), IN3,TP4, WD3,HT4,BF1,    BA,  BG,(APTR)BB(0), Z, OKTEXT, Z,  Z, 3, 0 },
  290. { G(5), IN4,TP4, WD4,HT4,BF2,    BA,  BG,(APTR)BB(1), Z, NOTEXT, Z,  Z, 4, 0 },
  291. { G(6), IN6,TP4, WD6,HT4,BF1,    BA,  BG,(APTR)BB(2), Z, VLTEXT, Z,  Z, 5, 0 },
  292. { G(7), IN7,TP4, WD7,HT4,BF1,    BA,  BG,(APTR)BB(3), Z, PRTEXT, Z,  Z, 6, 0 },
  293. { NULL, IN5,TP5, WD5,HT5,PF,     PA,  PG, IMAG, Z,   Z, Z,  PROP, 7, 0 }
  294. };
  295.  
  296. static struct NewWindow STD_NewWindow = {
  297.     WININ, WINTP, WINWD, WINHT, -1, -1,
  298.     REFRESHWINDOW|MOUSEBUTTONS|GADGETUP|CLOSEWINDOW,
  299.     WINDOWDRAG|WINDOWDEPTH|WINDOWCLOSE|SIMPLE_REFRESH|ACTIVATE,
  300.     G(0), NULL, (UBYTE *)"File Name Requestor",
  301.     NULL, NULL, 0, 0, 0, 0, CUSTOMSCREEN
  302. };
  303. static struct Window *STD_Window;
  304.  
  305. #define NVEC 6
  306.  
  307. static SHORT Vectors[NVEC*2] = {
  308.     BIN+1, BTP,
  309.     BIN+1, BTP+BHT,
  310.     BIN+BWD, BTP+BHT,
  311.     BIN+BWD, BTP,
  312.     BIN, BTP,
  313.     BIN, BTP+BHT
  314. };
  315.  
  316. static struct Border STD_FileBox = {
  317.     0, 0, FP, BP, JAM1, NVEC, Vectors, NULL
  318. };
  319.  
  320. static struct IntuiText STD_Text[3] = {
  321.     { FP, BP, JAM2, 0, 0, NULL, (UBYTE *)"Directory:", NULL },
  322.     { FP, BP, JAM2, 0, 0, NULL, (UBYTE *)"File Name:", NULL },
  323.     { FP, BP, JAM2, 0, 0, NULL, (UBYTE *)"Pattern:", NULL }
  324. };
  325.  
  326. static OpenFileWindow()
  327. {
  328.     extern struct IntuitionBase *IntuitionBase;
  329.     int i;
  330.  
  331.     /* Rebuild gadget list */
  332.     STD_NewWindow.FirstGadget = &STD_Gadget[0];
  333.     for(i = 0; i < GADGETS; i++) {
  334.         STD_Gadget[i].NextGadget = (i==GADGETS-1)?(0):(&STD_Gadget[i+1]);
  335.     }
  336.     for(i = 0; i < STRINGS; i++) {
  337.         STD_String[i].BufferPos = strlen(SBuffer[i]);
  338.         STD_String[i].DispPos = 0;
  339.     }
  340.     STD_Prop.VertBody = 0xFFFF;
  341.     STD_Prop.VertPot = 0;
  342.     STD_NewWindow.Screen = stdscreen;
  343.  
  344.     if(!(STD_Window = OpenWindow(&STD_NewWindow))) {
  345.             printf("Couldn't open file requester\n");
  346.         return 0;
  347.     }
  348.  
  349.     /* This  line will activate a string gadget    */
  350.    ActivateGadget(G(1),STD_Window,0L);
  351.  
  352.     CalcPropGadget();
  353.     PaintFileWindow();
  354.     return 1;
  355. }
  356.  
  357. static CloseFileWindow()
  358. {
  359.     STD_NewWindow.LeftEdge = STD_Window->LeftEdge;
  360.     STD_NewWindow.TopEdge = STD_Window->TopEdge;
  361.     if(STD_Window)
  362.         CloseWindow(STD_Window);
  363. }
  364.  
  365. static int State;
  366.  
  367. #define INITIAL 0
  368. #define DIRECTORY 1
  369.  
  370. static PaintFileWindow()
  371. {
  372.     DrawBorder(STD_Window->RPort, &STD_FileBox, 0, 0);
  373.     PrintIText(STD_Window->RPort, &STD_Text[0], LEFTMAR, TP1);
  374.     PrintIText(STD_Window->RPort, &STD_Text[1], LEFTMAR, TP2);
  375.     PrintIText(STD_Window->RPort, &STD_Text[2], LEFTMAR, TP3);
  376.     if(State == DIRECTORY) PrintFileNames();
  377. }
  378.  
  379. static int FirstFile;
  380. static int Selected;
  381. static int NumFiles;
  382. static struct dirent {
  383.     struct dirent *nextfile;
  384.     SHORT filetype;
  385.     char *filename;
  386. } *NameList, **NameTable;
  387.  
  388. #define FILETYPE 0
  389. #define DIRTYPE 1
  390. #define VOLTYPE 2
  391.  
  392. static PrintFileNames()
  393. {
  394.     int i;
  395.  
  396.     for(i = 0; i < MAXFILES; i++) {
  397.         SetBPen(STD_Window->RPort, BP);
  398.         SetAPen(STD_Window->RPort, BP);
  399.         RectFill(STD_Window->RPort,
  400.             HOMEX, HOMEY+i*CHSIZ,
  401.             LASTX, HOMEY+(i+1)*CHSIZ);
  402.         if(i+FirstFile < NumFiles)
  403.             PrintName(i+FirstFile, i+FirstFile==Selected);
  404.     }
  405. }
  406.  
  407. static PrintName(file, hilite)
  408. int file;
  409. int hilite;
  410. {
  411.     int i;
  412.  
  413.     i = file - FirstFile;
  414.  
  415.     Move(STD_Window->RPort, HOMEX, HOMEY+i*CHSIZ+BASELINE);
  416.     if(hilite == 0) {
  417.         SetBPen(STD_Window->RPort, BP);
  418.         if(NameTable[file]->filetype == FILETYPE)
  419.             SetAPen(STD_Window->RPort, FP);
  420.         else
  421.             SetAPen(STD_Window->RPort, 3);
  422.     } else {
  423.         SetAPen(STD_Window->RPort, BP);
  424.         if(NameTable[file]->filetype == FILETYPE)
  425.             SetBPen(STD_Window->RPort, FP);
  426.         else
  427.             SetBPen(STD_Window->RPort, 3);
  428.     }
  429.     Text(STD_Window->RPort,
  430.         NameTable[file]->filename,
  431.         strlen(NameTable[file]->filename));
  432. }
  433.  
  434. static CalcPropGadget()
  435. {
  436.     int VertPot, VertBody;
  437.  
  438.     if(State == INITIAL) return;
  439.  
  440.     if(NumFiles<=MAXFILES) {
  441.         VertBody = 0xFFFF;
  442.         VertPot = 0;
  443.         FirstFile = 0;
  444.     } else {
  445.         VertBody = ((MAXFILES<<16)-1) / NumFiles;
  446.         VertPot = 0;
  447.         FirstFile = 0;
  448.     }
  449.  
  450.     ModifyProp(&STD_Gadget[BARID], STD_Window, NULL,
  451.         STD_Prop.Flags, 0, VertPot, 0, VertBody);
  452. }
  453.  
  454. static CalcFilePosition()
  455. {
  456.     int old_pos;
  457.  
  458.     if(State == INITIAL) return;
  459.  
  460.     old_pos = FirstFile;
  461.     if(NumFiles<=MAXFILES)
  462.         FirstFile = 0;
  463.     else {
  464.         int VertPot = STD_Prop.VertPot;
  465.  
  466.         FirstFile = ((VertPot+1)*(NumFiles-MAXFILES))>>16;
  467.     }
  468.     if(old_pos != FirstFile)
  469.         PrintFileNames();
  470. }
  471.  
  472. FreeList(list)
  473. struct dirent *list;
  474. {
  475.     struct dirent *ptr;
  476.  
  477.     while(list) {
  478.         ptr = list->nextfile;
  479.         if(list->filename) free(list->filename);
  480.         free(list);
  481.         list = ptr;
  482.     }
  483. }
  484.  
  485. static ReadNewDir()
  486. {
  487.     struct dirent *NewList, **NewTable, *ptr;
  488.     int NewCount;
  489.     struct FileInfoBlock *FIB;
  490.     BPTR dirlock;
  491.  
  492.     if(State != DIRECTORY) {
  493.         NameTable = 0;
  494.         NameList = 0;
  495.     }
  496.     if(DirName[0])
  497.         dirlock = Lock(DirName, ACCESS_READ);
  498.     else {
  499.         BPTR ram;
  500.         ram = Lock("RAM:", ACCESS_READ);
  501.         dirlock = CurrentDir(ram);
  502.         CurrentDir(dirlock);
  503.         UnLock(ram);
  504.     }
  505.     if(dirlock==0)
  506.         return 0;
  507.  
  508.     /* FIB must be long word aligned, and aztec doesn't guarantee this, so: */
  509.     if((FIB = AllocMem(sizeof(struct FileInfoBlock), MEMF_PUBLIC)) == 0) {
  510.         UnLock(dirlock);
  511.         return 0;
  512.     }
  513.     if(!Examine(dirlock, FIB)) {
  514.         UnLock(dirlock);
  515.         FreeMem(FIB, sizeof(struct FileInfoBlock));
  516.         return 0;
  517.     }
  518.     if(FIB->fib_DirEntryType < 0) {
  519.         UnLock(dirlock);
  520.         FreeMem(FIB, sizeof(struct FileInfoBlock));
  521.         return 0;
  522.     }
  523.     NewList = 0;
  524.     NewCount = 0;
  525.     while(ExNext(dirlock, FIB)) {
  526.         NewCount += 1;
  527.         ptr = (struct dirent *)malloc(sizeof(struct dirent));
  528.         if(ptr==0) {
  529.             FreeList(NewList);
  530.             UnLock(dirlock);
  531.             FreeMem(FIB, sizeof(struct FileInfoBlock));
  532.             return 0;
  533.         }
  534.         ptr->nextfile = NewList;
  535.         ptr->filetype = (FIB->fib_DirEntryType<0)?FILETYPE:DIRTYPE;
  536.         ptr->filename = malloc(strlen(FIB->fib_FileName)+1);
  537.         if(ptr->filename == 0) {
  538.             FreeList(ptr);
  539.             UnLock(dirlock);
  540.             FreeMem(FIB, sizeof(struct FileInfoBlock));
  541.             return 0;
  542.         }
  543.         strcpy(ptr->filename, FIB->fib_FileName);
  544.         NewList = ptr;
  545.     }
  546.     FreeMem(FIB, sizeof(struct FileInfoBlock));
  547.     if(DirName[0]) {
  548.         UnLock(dirlock);
  549.     }
  550.     NewTable = malloc(sizeof(struct dirent *)*NewCount);
  551.     if(NewTable==0) {
  552.         FreeList(NewList);
  553.         return 0;
  554.     }
  555.     FreeList(NameList);
  556.     NameList = NewList;
  557.     if(NameTable) free(NameTable);
  558.     NameTable = NewTable;
  559.  
  560.     if(PatName[0]==0)
  561.         SetPatName("#?");
  562.  
  563.     State = DIRECTORY;
  564.     Selected = -1;
  565.  
  566.     ReCalcPattern();
  567. }
  568.  
  569. static ReadVol()
  570. {
  571.     struct dirent *NewList, **NewTable, *ptr;
  572.     int NewCount;
  573.     char name[MAXNAME];
  574.  
  575.     if(State != DIRECTORY) {
  576.         NameTable = 0;
  577.         NameList = 0;
  578.     }
  579.     OpenVolList();
  580.     NewList = 0;
  581.     NewCount = 0;
  582.     while(ReadVolList(name)) {
  583.         NewCount += 1;
  584.         ptr = (struct dirent *)malloc(sizeof(struct dirent));
  585.         if(ptr==0) {
  586.             FreeList(NewList);
  587.             return 0;
  588.         }
  589.         ptr->nextfile = NewList;
  590.         ptr->filetype = VOLTYPE;
  591.         ptr->filename = malloc(strlen(name)+1);
  592.         if(ptr->filename == 0) {
  593.             FreeList(ptr);
  594.             return 0;
  595.         }
  596.         strcpy(ptr->filename, name);
  597.         NewList = ptr;
  598.     }
  599.     CloseVolList();
  600.     NewTable = malloc(sizeof(struct dirent *)*NewCount);
  601.     if(NewTable==0) {
  602.         FreeList(NewList);
  603.         return 0;
  604.     }
  605.     FreeList(NameList);
  606.     NameList = NewList;
  607.     if(NameTable) free(NameTable);
  608.     NameTable = NewTable;
  609.  
  610.     if(PatName[0]==0)
  611.         SetPatName("#?");
  612.  
  613.     State = DIRECTORY;
  614.     Selected = -1;
  615.  
  616.     ReCalcPattern();
  617. }
  618.  
  619. static WORD PatCode[128];
  620.  
  621. static patcomp()
  622. {
  623.     /* This is a judgement call: that no pattern should be equivalent
  624.        to "#?". Perhaps it should do this invisibly, by adding a
  625.        pointer to the real pattern name and making it PatName or "#?"
  626.        as appropriate. */
  627.  
  628.     if(!PatName[0])
  629.         SetPatName("#?");
  630.     return CmplPat(PatName, PatCode);
  631. }
  632.  
  633. static patmatch(name)
  634. {
  635.     return Match(PatName, PatCode, name);
  636. }
  637.  
  638. /* this routine does a true dictionary search:
  639.  *
  640.  *        Devs < devs but Devs > devices
  641.  */
  642. static table_compare(p1, p2)
  643. struct dirent **p1, **p2;
  644. {
  645.     char *s1, *s2;
  646.     char c1, c2;
  647.     char firstdiff;
  648.  
  649.     s1 = (*p1)->filename;
  650.     s2 = (*p2)->filename;
  651.     firstdiff = 0;
  652.  
  653.     while(*s1 && *s2) {
  654.         c1 = *s1++;
  655.         c2 = *s2++;
  656.         if(firstdiff==0)
  657.             firstdiff = c1 - c2;
  658.         if(c1>='A' && c1<='Z') c1 = c1+'@';
  659.         if(c2>='A' && c2<='Z') c2 = c2+'@';
  660.         if(c1 != c2)
  661.             return c1 - c2;
  662.     }
  663.     return firstdiff;
  664. }
  665.  
  666. static sort_table()
  667. {
  668.     qsort(NameTable, NumFiles, sizeof(struct dirent *), table_compare);
  669.     return 1;
  670. }
  671.  
  672. static ReCalcPattern()
  673. {
  674.     if(State != DIRECTORY)
  675.         ReadNewDir();
  676.     else {
  677.         struct dirent *ptr;
  678.         patcomp();
  679.  
  680.         NumFiles = 0;
  681.         for(ptr = NameList; ptr; ptr=ptr->nextfile) {
  682.             /* Directories always match. Is this good? */
  683.             if(ptr->filetype == DIRTYPE ||
  684.                ptr->filetype == VOLTYPE ||
  685.                patmatch(ptr->filename)) {
  686.                 NameTable[NumFiles] = ptr;
  687.                 NumFiles++;
  688.             }
  689.         }
  690.         sort_table();
  691.         CalcPropGadget();
  692.         Selected = -1;
  693.         PrintFileNames();
  694.     }
  695. }
  696.  
  697. static SetGadgetText(id, text)
  698. int id;
  699. char *text;
  700. {
  701.     int position;
  702.  
  703.     position = RemoveGadget(STD_Window, G(id));
  704.     if(position != -1) {
  705.         strcpy(SBuffer[id], text);
  706.         STD_String[id].BufferPos = strlen(text);
  707.         position = AddGadget(STD_Window, G(id), -1);
  708.         if(position != -1)
  709.             RefreshGadgets(G(id), STD_Window, NULL);
  710.     }
  711. }
  712.  
  713. static SetDirName(name)
  714. char *name;
  715. {
  716.     char buffer[MAXFULL+1], *ptr;
  717.     int index;
  718.     char lastchar;
  719.  
  720.     /* Can't enter a file name too long. */
  721.     if(strlen(DirName) + strlen(name) + 1 > MAXFULL) {
  722.         DisplayBeep();
  723.         return 0;
  724.     }
  725.     index = 0;
  726.     lastchar = 0;
  727.     for(ptr = DirName; *ptr; ptr++)
  728.         buffer[index++] = lastchar = *ptr;
  729.     if(lastchar!='/' && lastchar!=':' && lastchar!=0)
  730.         buffer[index++] = '/';
  731.     strcpy(&buffer[index], name);
  732.     SetGadgetText(DIRID, buffer);
  733.     SetGadgetText(FILID, "");
  734.     return 1;
  735. }
  736.  
  737. static ReadParDir()
  738. {
  739.     int i;
  740.     int ptr;
  741.  
  742.     ptr = -1;
  743.     for(i = 0; DirName[i]; i++)
  744.         if(DirName[i]==':' || DirName[i]=='/')
  745.             ptr = i;
  746.     if(ptr>=0) {
  747.         SetGadgetText(FILID, &DirName[ptr+1]);
  748.         if(ptr==0 || DirName[ptr]==':')
  749.             ptr++;
  750.         DirName[ptr] = 0;
  751.         SetGadgetText(DIRID, DirName);
  752.     } else {
  753.         SetGadgetText(FILID, DirName);
  754.         if(i)
  755.             SetGadgetText(DIRID, "");
  756.         else
  757.             SetGadgetText(DIRID, "/");
  758.     }
  759.     ReadNewDir();
  760.     return 1;
  761. }
  762.  
  763. static SetFileName(name)
  764. char *name;
  765. {
  766.     /* Can't enter a file name too long. */
  767.     if(strlen(DirName) + strlen(name) + 1 > MAXFULL) {
  768.         DisplayBeep();
  769.         return 0;
  770.     }
  771.     SetGadgetText(FILID, name);
  772.     return 1;
  773. }
  774.  
  775. static SetPatName(name)
  776. char *name;
  777. {
  778.     SetGadgetText(PATID, name);
  779. }
  780.  
  781. static ProcessGadget(id)
  782. int id;
  783. {
  784.     switch(id) {
  785.         case DIRID: ReadNewDir(); break;
  786.         case FILID: DoneFlag = 1; break;
  787.         case PATID: ReCalcPattern(); break;
  788.         case BARID: CalcFilePosition(); break;
  789.         case YESID: DoneFlag = 1; break;
  790.         case CANID: DoneFlag = -1; break;
  791.         case VOLID: ReadVol(); break;
  792.         case PARID: ReadParDir(); break;
  793.     }
  794. }
  795.  
  796. static ProcessMouse(x, y, code, seconds, micros)
  797. int x, y, code;
  798. {
  799.     int NewSelected;
  800.     static int oseconds = 0, omicros = 0;
  801.  
  802.     if(x<HOMEX || y<HOMEY || x>=LASTX || y>=LASTY)
  803.         return;
  804.     if((code&SELECTUP) == SELECTUP)
  805.         return;
  806.     if(State != DIRECTORY) {
  807.         ReadNewDir();
  808.         return;
  809.     }
  810.     NewSelected = (y-HOMEY)/CHSIZ + FirstFile;
  811.     if(NewSelected == Selected) {
  812.         if(Selected != -1) {
  813.             if(DoubleClick(oseconds, omicros, seconds, micros)) {
  814.                 if(NameTable[Selected]->filetype == DIRTYPE) {
  815.                     if(SetDirName(NameTable[Selected]->filename))
  816.                         ReadNewDir();
  817.                 } else if(NameTable[Selected]->filetype == VOLTYPE) {
  818.                     SetGadgetText(DIRID, NameTable[Selected]->filename);
  819.                     SetGadgetText(FILID, "");
  820.                     ReadNewDir();
  821.                 } else {
  822.                     if(!SetFileName(NameTable[Selected]->filename))
  823.                         Selected = -1;
  824.                     DoneFlag = 1;
  825.                 }
  826.             }
  827.         }
  828.     } else {
  829.         if(Selected != -1 &&
  830.            Selected>=FirstFile && Selected<FirstFile+MAXFILES)
  831.             PrintName(Selected, 0);
  832.         Selected = NewSelected;
  833.         if(Selected>=NumFiles)
  834.             Selected = -1;
  835.         else {
  836.             if(SetFileName(NameTable[Selected]->filename))
  837.                 PrintName(Selected, 1);
  838.             else
  839.                 Selected = -1;
  840.         }
  841.     }
  842.     oseconds = seconds;
  843.     omicros = micros;
  844. }
  845.  
  846. stdfile(title, deffile, defpat, name)
  847. char *title, *deffile, *defpat, *name;
  848. {
  849.     if(title)
  850.         STD_NewWindow.Title = (UBYTE *)title;
  851.     else
  852.         STD_NewWindow.Title = (UBYTE *)"Enter File Name";
  853.     if(deffile) {
  854.         int i;
  855.         for(i = strlen(deffile)-1; i>=0; i--) {
  856.             if(deffile[i]==':' || deffile[i]=='/') {
  857.                 int hold;
  858.                 strcpy(FileName, &deffile[i+1]);
  859.                 if(deffile[i]==':')
  860.                     i++;
  861.                 hold = deffile[i];
  862.                 deffile[i] = 0;
  863.                 strcpy(DirName, deffile);
  864.                 deffile[i] = hold;
  865.                 break;
  866.             }
  867.         }
  868.         if(i<0) {
  869.             strcpy(FileName, deffile);
  870.             DirName[0] = 0;
  871.         }
  872.     } else {
  873.         DirName[0] = 0;
  874.         FileName[0] = 0;
  875.     }
  876.     if(defpat)
  877.         strcpy(PatName, defpat);
  878.     else
  879.         PatName[0] = 0;
  880.  
  881.     State = INITIAL;
  882.     NameTable = 0;
  883.     NameList = 0;
  884.  
  885.     if(OpenFileWindow()) {
  886.         struct IntuiMessage *msg;
  887.         DoneFlag = 0;
  888.         while(!DoneFlag) {
  889.             Wait(1<<STD_Window->UserPort->mp_SigBit);
  890.             while(msg = GetMsg(STD_Window->UserPort)) {
  891.                 switch(msg->Class) {
  892.                     case CLOSEWINDOW:
  893.                         DoneFlag = -1;
  894.                         break;
  895.                     case MOUSEBUTTONS:
  896.                         ProcessMouse(msg->MouseX, msg->MouseY,
  897.                             msg->Code,
  898.                             msg->Seconds, msg->Micros);
  899.                         break;
  900.                     case GADGETUP:
  901.                         ProcessGadget(
  902.                             ((struct Gadget *)msg->IAddress)->GadgetID
  903.                         );
  904.                         break;
  905.                     case REFRESHWINDOW:
  906.                         BeginRefresh(STD_Window);
  907.                         PaintFileWindow();
  908.                         EndRefresh(STD_Window, 1);
  909.                         break;
  910.                 }
  911.                 ReplyMsg(msg);
  912.             }
  913.         }
  914.  
  915.         CloseFileWindow();
  916.     }
  917.     else return 0;
  918.  
  919.     FreeList(NameList);
  920.     if(NameTable) free(NameTable);
  921.  
  922.     if(DoneFlag==1) {
  923.         int len;
  924.  
  925.         strcpy(name, DirName);
  926.         if(FileName[0]) {
  927.             if(len = strlen(name))
  928.                 if(name[len-1]!=':')
  929.                     strcat(name, "/");
  930.             strcat(name, FileName);
  931.             return 1;
  932.         }
  933.  
  934.         /* Here the user has accepted the name without providing a file
  935.            name. I return true, but false may be more appropriate. What
  936.            do you think? */
  937.         return 1;
  938.     }
  939.     return 0;
  940. }
  941.